Skip to content

nodes: improve modular cabinet constraints and finishes - #719

Open
sudhir9297 wants to merge 44 commits into
pascalorg:mainfrom
sudhir9297:t3code/improve-kitchen-cabinets
Open

nodes: improve modular cabinet constraints and finishes#719
sudhir9297 wants to merge 44 commits into
pascalorg:mainfrom
sudhir9297:t3code/improve-kitchen-cabinets

Conversation

@sudhir9297

@sudhir9297 sudhir9297 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

  • Improves modular cabinet sizing with metric and US dimension profiles, standard widths, reveal presets, planning validation, and configurable top-cabinet or trim ceiling finishes.
  • Reworks constrained run reflow so wider appliance presets consume available wall slack or resize eligible neighboring base cabinets while preserving two-wall extents.
  • Keeps L-shaped corner runs governed by the original straight run's perpendicular-wall constraints, resynchronizes derived corner geometry after width changes, and rejects changes only when real donor capacity is insufficient.
  • Adds focused coverage for straight, nested, chained, one-wall, two-wall, and two-ended L-run scenarios, plus cabinet finish and sizing behavior.

How to test

  1. Run bun dev, open the editor, and create a straight modular base-cabinet run with perpendicular walls constraining both ends.
  2. Add an L Left or L Right return at either end, then change a center or end module to a wider refrigerator preset. Confirm the original straight run keeps its wall-bounded extent, eligible base cabinets absorb the width change, and the L return stays inside the walls.
  3. Switch the refrigerator back to a narrower preset. Confirm donated widths are restored and the L footprint remains anchored.
  4. Remove one of the original run's perpendicular end walls and repeat the width changes. Confirm available wall slack is consumed first and the run moves only toward the open side without treating the derived L-leg wall as a source-run constraint.
  5. Repeat with L returns on both ends and with a nested L-leg selected. Confirm constraints still come from the original straight run and valid refrigerator changes do not report “No space in this run.”
  6. In the cabinet panels, verify standard dimensions, module widths, reveal gaps, planning warnings, and Top / Ceiling controls. Apply Top Cabinet and Trim / Soffit finishes and use Fill to ceiling.
  7. Run bun test packages/nodes/src/cabinet, bun run check-types, bun run check, and bun run build.

Screenshots / screen recording

To be added — this is a visual and interactive cabinet-layout change.

Checklist

  • I've tested this locally with bun dev
  • My code follows the existing code style (run bun check to verify)
  • I've updated relevant documentation (if applicable)
  • This PR targets the main branch

Note

Medium Risk
Large changes to cabinet schema versions, run reflow/corner logic, and default dimensions affect saved scenes and layout behavior, though coverage is extensive.

Overview
This PR extends modular kitchen cabinets with metric-first defaults (600 mm depth family), catalog-style dimension profiles, standard widths, reveal presets, and schema fields for top / ceiling finish (none, stacked top cabinet, or trim/soffit) with matching 3D geometry and bounds.

Run layout and presets are reworked: perpendicular-wall slack and eligible neighbor “donors” drive width changes when applying wider appliance presets, while two-wall runs keep their overall extent. L-corner derived runs nest under source runs in the graph; reflow respects the original straight run’s wall constraints (not the leg’s walls), resyncs corner geometry after width changes, and adds broad regression tests for reflow, stacks, and finishes.

Appliance stacks drop automatic filler drawers above fridges; dishwashers and similar transitions fill the carcass height correctly. The editor Build tab gains a Kitchen tile that arms the modular cabinet tool from the catalog. Research docs on ceiling gaps and modular planning are added; graph validation accepts derived L-corner cabinet trees.

Reviewed by Cursor Bugbot for commit c7ab1d9. Bugbot is set up for automated code reviews on this repo. Configure here.

sudhir9297 and others added 30 commits May 19, 2026 02:59
Items (e.g. solar panels) can now be placed on sloped roof surfaces.
The placement system computes euler rotation from the roof surface
normal so items sit flush on the slope instead of going inside.

- Add roofStrategy to placement-strategies with enter/move/click/leave
- Wire roof:enter/move/click/leave events in the placement coordinator
- Add calculateRoofRotation in placement-math using surface normals
- Support full 3D cursor rotation for sloped surfaces
- Items on roofs are parented to the level with world-space rotation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(node.showPlinth ? node.plinthHeight : 0) +
node.carcassHeight +
(node.withCountertop ? node.countertopThickness : 0)
return Math.max(0.05, ceilingHeight - currentTop)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fill to ceiling overshoots

Medium Severity

cabinetCeilingGap always returns at least 0.05, even when the module already reaches or exceeds the ceiling. Fill to ceiling then sets topFinishHeight to that floor, so the top finish can poke through the ceiling instead of becoming a zero or near-zero closure.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 85476a4. Configure here.

return stack.length > 0 && stack.every((compartment) => isHoodCompartmentType(compartment.type))
}

function cabinetModuleHeightHandleVisible(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Height handle under finish

Low Severity

The new module height handle is placed with cabinetTotalHeight, which excludes topFinishHeight, while local bounds now include the top finish. With Top Cabinet or Trim active, the Y handle sits inside the finish volume instead of above the full composition.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 85476a4. Configure here.


const stack = stackForCabinet(node)
const planningRun = node.type === 'cabinet' ? node : parentRun
const planningReport = planningRun ? validateCabinetRun(planningRun, modules) : null

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wall top finish unchecked

Low Severity

Planning checks run validateCabinetRun only on the parent run’s direct modules. Nested wall cabinets—the modules that commonly use Top / Ceiling—are omitted, and selecting a wall child clears parentRun, so top-cabinet-too-short never surfaces for them.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 85476a4. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

There are 6 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c7ab1d9. Configure here.

CABINET_METRIC_DEFAULTS,
findLevelAncestorId,
selectionProxyIdFromMetadata,
} from '@pascal-app/core'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Footprints omit top finish height

Medium Severity

Selection and local bounds now include topFinishHeight for top-cabinet and trim finishes, but floor-placed footprints still size height with cabinetTotalHeight only. Collision and placement checks can treat the upper finish as empty space and allow overlaps with the new ceiling volumes.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c7ab1d9. Configure here.

.map((module) => [module.id, MIN_TRIMMED_CORNER_PRESET_WIDTH]),
),
maximumWidth: MAX_CABINET_WIDTH,
maximumWidthById,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nested leg uses wrong wall axis

High Severity

When reflowing a nested L-leg, wall constraints are taken from the source straight run, then applied as left/right flags while packing the leg’s own local X modules. For a one-wall source, growth direction and slack consumption follow the source lateral axis on the perpendicular leg, so the return can shift or expand along the wrong direction.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c7ab1d9. Configure here.

useScene.getState().nodes as Record<AnyNodeId, AnyNode>,
),
})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fill to ceiling ignores schema max

Low Severity

Fill to ceiling writes cabinetCeilingGap straight into topFinishHeight. That gap is only floored at 0.05 and is not capped at the field’s 1.2 maximum (or the slider max), so taller rooms can produce out-of-range finish heights.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c7ab1d9. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant